﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TeamFoundation.ContinuousMerge
{
    /// <summary>
    /// Represents the core extensions to a variety of classes.
    /// </summary>
    public static class CoreExtensions
    {
        /// <summary>
        /// Converts a connection string for SQL Server to an entity connection string.
        /// </summary>
        /// <param name="sqlConnectionString">The SQL Server connection string.</param>
        /// <returns>The entity connection string.</returns>
        public static string BuildEntityConnectionString(this string sqlConnectionString, string provider)
        {
            if (sqlConnectionString == null)
                throw new ArgumentNullException("sqlConnectionString");
            if (provider == null)
                throw new ArgumentNullException("provider");

            const string format = "metadata=res://*/Model.Database.csdl|res://*/Model.Database.ssdl|res://*/Model.Database.msl;provider={0};provider connection string=\"{1}\"";
            return string.Format(format, provider, sqlConnectionString);
        }

        /// <summary>
        /// Converts a connection string for SQL Server to an entity connection string.
        /// </summary>
        /// <param name="sqlConnectionString">The SQL Server connection string.</param>
        /// <returns>The entity connection string.</returns>
        public static string BuildEntityConnectionString(this string sqlConnectionString, Type provider)
        {
            if (provider == null)
                throw new ArgumentNullException("provider");

            return sqlConnectionString.BuildEntityConnectionString(provider.Namespace);
        }

        /// <summary>
        /// Converts a connection string for SQL Server to an entity connection string.
        /// </summary>
        /// <param name="sqlConnectionString">The SQL Server connection string.</param>
        /// <returns>The entity connection string.</returns>
        public static string BuildEntityConnectionString<TProvider>(this string sqlConnectionString)
        {
            return sqlConnectionString.BuildEntityConnectionString(typeof(TProvider));
        }


        /// <summary>
        /// Converts a connection string for SQL Server to an entity connection string.
        /// </summary>
        /// <param name="sqlConnectionString">The SQL Server connection string.</param>
        /// <returns>The entity connection string.</returns>
        public static string BuildEntityConnectionString(this string sqlConnectionString)
        {
            return sqlConnectionString.BuildEntityConnectionString<System.Data.SqlClient.SqlConnection>();
        }

        /// <summary>
        /// Gets a typed instance of a service.
        /// </summary>
        /// <typeparam name="T">The type to get.</typeparam>
        /// <param name="provider">The <see cref="IServiceProvider"/> to query.</param>
        /// <returns>An instance of <see cref="T"/> or null if the service was not found or was not of the correct type.</returns>
        public static T GetService<T>(this IServiceProvider provider)
            where T : class
        {
            return provider.GetService(typeof(T)) as T;
        }

        /// <summary>
        /// Adds a new value to a dictionary that contains lists of values.
        /// </summary>
        /// <typeparam name="TKey">The key type.</typeparam>
        /// <typeparam name="TValue">The single value type.</typeparam>
        /// <typeparam name="TDictionary">The dictionary type.</typeparam>
        /// <typeparam name="TList">The list type.</typeparam>
        /// <param name="dictionary">The dictionary/flyweight.</param>
        /// <param name="key">The key.</param>
        /// <param name="value">The value to add.</param>
        /// <param name="createList">A <see cref="Func{TList}"/> to create a new <typeparamref name="TList"/>.</param>
        public static bool AddFlyweight<TKey, TValue, TDictionary, TList>(this TDictionary dictionary, TKey key, TValue value, Func<TList> createList)
            where TDictionary : IDictionary<TKey, TList>
            where TList : ICollection<TValue>
        {
            TList values;
            if (!dictionary.TryGetValue(key, out values))
                dictionary.Add(key, values = createList());
            if (!values.Contains(value))
                values.Add(value);
            else
                return false;
            return true;
        }
    }
}
